#!/usr/bin/env python
#coding=utf-8

import os, re, datetime, sys, subprocess

DEFAULT_LICENSE = "gpl3"
CONTRIBUTOR_LICENSE = "mit"
LICENSE_DIR = "Documentation/Licenses"

# The following regex parses license comment blocks and its part out of a complete source file.
reParseLicenseCommentBlocks = re.compile(ur'(\/\*\n\s\*\sCopyright \(c\) (?P<startYear>\d\d\d\d)(-(?P<endYear>\d\d\d\d))? (?P<author>[^\n\.]*)\.?\n.\* (?P<license>[^\n]*)\n \* (?P<seeMore>[^\n]+)\n *\*\/)')

class License :
	def __init__(self, name, file) :
		self.name = name
		self.file = file

licenses = {
		"default": License("All rights reserved.", "See the COPYING file for more information."),
		"gpl3" : License("Licensed under the GNU General Public License v3.", "See " + LICENSE_DIR + "/" + "GPLv3.txt" + " for more information."),
		"mit" : License("Licensed under the MIT License.", "See " + LICENSE_DIR + "/" +  "MIT.txt" + " for more information."),
	}

class Copyright :
	def __init__(self, author, year, license) :
		self.author = author
		self.year = year
		self.license = license

	def to_string(self, comment_chars) :
		return "\n".join([
			comment_chars[0],
			comment_chars[1] + " Copyright (c) %(year)s %(name)s" % {"year" : self.year, "name" : self.author },
			comment_chars[1] + licenses[self.license].name,
			comment_chars[1] + licenses[self.license].file,
			comment_chars[2],
			"\n"])
	def __str__(self):
		return """/*
 * Copyright (c) %s %s.
 * %s
 * %s
 */
""" % (self.year, self.author, licenses[self.license].name, licenses[self.license].file)

class ContentRef :
	def __init__(self, begin, end, content):
		self.begin = begin
		self.end = end
		self.content = content

class CopyrightBlock :
	def __init__(self, yearBegin, yearEnd, author, license, seeMore, total):
		self.yearBegin = yearBegin
		self.yearEnd = yearEnd
		self.author = author
		self.license = license
		self.seeMore = seeMore
		self.total = total

def cref_from_group(match, group):
	if match.group(group):
		return ContentRef(match.start(group), match.end(group), match.group(group))
	else :
		return None

def parse_file_new(filename):
	copyrightBlocks = []
	with open(filename, 'r') as file:
		content = file.read()
		for match in re.finditer(reParseLicenseCommentBlocks, content):
			copyrightBlocks.append(CopyrightBlock(
				cref_from_group(match, "startYear"), 
				cref_from_group(match, "endYear"), 
				cref_from_group(match, "author"), 
				cref_from_group(match, "license"), 
				cref_from_group(match, "seeMore"), 
				cref_from_group(match, 0)))
	return copyrightBlocks

def get_userinfo() :
	p = subprocess.Popen("git config user.name", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=(os.name != "nt"))
	username = p.stdout.read().rstrip()
	p.stdin.close()
	if p.wait() != 0 :
		return None
	p = subprocess.Popen("git config user.email", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=(os.name != "nt"))
	email = p.stdout.read().rstrip()
	p.stdin.close()
	if p.wait() != 0 :
		return None
	return (username, email)

def get_copyright(username, email) :
	if email in ["git@el-tramo.be", "git@kismith.co.uk"] :
		license = DEFAULT_LICENSE
	else :
		license = CONTRIBUTOR_LICENSE
	return Copyright(username, datetime.date.today().strftime("%Y"), license)

def get_copyright_setting(username, email) :
	config = os.getenv("SWIFT_LICENSE_CONFIG")
	if config :
		copyrightHolder, license = config.split("|")
	else :
		if email.endswith("isode.com") or email in ["git@el-tramo.be", "git@kismith.co.uk", "tm@ayena.de"] :
			copyrightHolder, license = "Isode Limited", "default"
		else :
			copyrightHolder, license = username, "mit"
	return Copyright(copyrightHolder, datetime.date.today().year, license)

def check_copyright(filename, hints) :
	copyrightBlocks = parse_file_new(filename)
	if copyrightBlocks :
		# looking for copyright block for current author
		username, email = get_userinfo()
		copyrightSetting = get_copyright_setting(username, email)
		for block in copyrightBlocks :
			if block.author.content == copyrightSetting.author:
				year = block.yearBegin.content if not block.yearEnd else block.yearEnd.content
				if int(year) == copyrightSetting.year:
					return True
				else :
					if hints :
						print "Copyright block for " + copyrightSetting.author + " does not cover current year in: " + filename
					return False
		if hints :
			print "Missing copyright block for " + copyrightSetting.author + " in: " + filename
		return False
	else :
		if hints :
			print "No copyright found in: " + filename
		return False

def replace_data_in_file(filename, begin, end, replaceWith) :
	with open(filename, 'r') as file:
		content = file.read()
	with open(filename, 'w') as file:
		file.write(content[:begin] + replaceWith + content[end:])

def set_or_update_copyright(filename) :
	if check_copyright(filename, False) :
		print "No update required for file: " + filename
	else :
		copyrightBlocks = parse_file_new(filename)
		username, email = get_userinfo()
		copyrightSetting = get_copyright_setting(username, email)
		lastBlock = 0
		for block in copyrightBlocks :
			if block.author.content == copyrightSetting.author :
				if not block.yearEnd :
					# replace year with range
					replace_data_in_file(filename, block.yearBegin.begin, block.yearBegin.end, "%s-%s" % (block.yearBegin.content, str(copyrightSetting.year)))
				else :
					# replace end of range with current year
					replace_data_in_file(filename, block.yearEnd.begin, block.yearEnd.end, "%s" % str(copyrightSetting.year))
				return
			lastBlock = block.total.end

		# No copyright block found. Append a new one.
		replace_data_in_file(filename, lastBlock+1, lastBlock+1, "\n" + str(copyrightSetting))

def print_help() :
	print """Usage:
	Copyrighter.py check-copyright $filename
		Cheks for the existence of a copyright comment block.

	Copyrighter.py set-copyright $filename
		Adds or updates the existing copyright comment block.

	License setting:
		A users license configuration can be set via the SWIFT_LICENSE_CONFIG environment variable 
		in the format "$copyright holder|$license", e.g. "Jane Doe|mit". Possible values for 
		$license are default, mit and gpl.
	"""

if sys.argv[1] == "check-copyright" :
	file = sys.argv[2]
	if (file.endswith(".cpp") or file.endswith(".h")) and not "3rdParty" in file :
		if not check_copyright(file, True) :
			sys.exit(-1)
elif sys.argv[1] == "set-copyright" :
	file = sys.argv[2]
	set_or_update_copyright(file)
else :
	print "Unknown command: " + sys.argv[1]
	print_help()
	sys.exit(-1)
